/************************************************************
*	ProjectName:   LT2911R
*	FileName:	   LT2911R_INPUT_LVDS.c
*	BuildData:	   2020-05-20
*	Version：      V8.0
* 	Author:        xhguo
* 	Company:	   Lontium
************************************************************/

/*
V8.0 20200520
1. first release.

*/
#include "lt2911r_input_lvds.h"
#include "i2c.h"
#include "lt2911r_lvds_to_mipi.h"
#include "printf.h"

//#if defined(_lvds_to_mipi_)||defined(_lvds_to_lvds_)||defined(_lvds_to_ttl_)

void LT2911R_LvdsRxPhy(void)
{
	HDMI_WriteI2C_Byte(0xff, 0x82);
	HDMI_WriteI2C_Byte(0x02, 0x88); //lvds rx enable
#if (LVDS_INPUT_PIN_MAP)		//D3,D2,clk,D1,D0
	{
		HDMI_WriteI2C_Byte(0x05, 0x10); //rterm auto turn off disable
		HDMI_WriteI2C_Byte(0x0d, 0x10); //rterm auto turn off disable
	}
#else //D0,D1,D2,clk,D3
	{
		HDMI_WriteI2C_Byte(0x05, 0x11); //rterm auto turn off disable
		HDMI_WriteI2C_Byte(0x0d, 0x11); //rterm auto turn off disable
	}
#endif
	HDMI_WriteI2C_Byte(0xff, 0x81);
	HDMI_WriteI2C_Byte(0x20, 0x7f);
	HDMI_WriteI2C_Byte(0x20, 0xff); //mlrx calib reset
}

/****************************************************************
* funtion:  配置与LVDS 协议相关的内容，
* 例如Port 的个数； LVDS 的格式；DE mode or sync mode.
*
******************************************************************/

void LT2911R_LvdsRxDigital(struct video_timing *video_format)
{
	HDMI_WriteI2C_Byte(0xff, 0xd8);

	if (LVDS_PORT_CNT == 1) {
		HDMI_WriteI2C_Byte(0x10, 0x80 | LVDS_SYNC_POL); //0x80: 1port, 0x00: 2port
		printf("\r\n LvdsRxDigital: set lvds port count = 1");
	} else if (LVDS_PORT_CNT == 2) {
		HDMI_WriteI2C_Byte(0x10, 0x00 | LVDS_SYNC_POL); //0x80: 1port, 0x00: 2port
		printf("\r\n LvdsRxDigital: set lvds port count = 2");
	}

	else {
		printf("\r\n LvdsRxDigital: lvds port count error");
	}

#if LVDS_VID_FORMAT //JEIDA
	HDMI_WriteI2C_Byte(0x11, 0x40);
#endif

#if LVDS_SYNC_MODE
	HDMI_WriteI2C_Byte(0x1f, 0x20); //sync only mode
	HDMI_WriteI2C_Byte(0x20, (u8)(video_format->hfp / 256));
	HDMI_WriteI2C_Byte(0x21, (u8)(video_format->hfp % 256));

	HDMI_WriteI2C_Byte(0x22, (u8)(video_format->hs / 256));
	HDMI_WriteI2C_Byte(0x23, (u8)(video_format->hs % 256));

	HDMI_WriteI2C_Byte(0x24, (u8)(video_format->htotal / 256));
	HDMI_WriteI2C_Byte(0x25, (u8)(video_format->htotal % 256));

	HDMI_WriteI2C_Byte(0x26, (u8)(video_format->vfp % 256));
	HDMI_WriteI2C_Byte(0x27, (u8)(video_format->vs % 256));
#endif

#if (LVDS_INPUT_PIN_MAP) //D3,D2,clk,D1,D0
	{
		HDMI_WriteI2C_Byte(0xff, 0x86); //lvds lane swap
		HDMI_WriteI2C_Byte(0x33, 0x1b);
		HDMI_WriteI2C_Byte(0x34, 0x1b);
		printf("\r\n LT2911R_LvdsRxDigital: INPUT_PIN_MAP_1");
	}
#endif

#if LVDS_O_E_SWAP
	HDMI_WriteI2C_Byte(0xff, 0x86); //old even swap
	HDMI_WriteI2C_Byte(0x30, 0x4a);
#endif
	HDMI_WriteI2C_Byte(0xff, 0x81);
	HDMI_WriteI2C_Byte(0x10, 0xbe);
	HDMI_WriteI2C_Byte(0x10, 0xfe);
	HDMI_WriteI2C_Byte(0x0c, 0xeb);
	HDMI_WriteI2C_Byte(0x0c, 0xfb);
}

void LT2911R_LvdsRxPll(void)
{
	u8 reg_8712;
	HDMI_WriteI2C_Byte(0xff, 0x82); //RG_RXPLL_PD
	HDMI_WriteI2C_Byte(0x25, 0x07); //rxpll select adaptive pll, and 3.5GHz.
	HDMI_WriteI2C_Byte(0x26, LVDS_CLK_PHASE);
	HDMI_WriteI2C_Byte(0x27, 0x32); //RG_RXPLL_DOUB_CLK_EN

	if (LVDS_PORT_CNT == 1) {
		HDMI_WriteI2C_Byte(0x24, 0x24); //RXPLL_LVDSCLK_MUXSEL,PIXCLK_MUXSEL	0x2c.
		HDMI_WriteI2C_Byte(0x28, 0x04); //0x64
		printf("\r\n LvdsRxPll: set lvds port count = 1");
	} else if (LVDS_PORT_CNT == 2) {
		HDMI_WriteI2C_Byte(0x24, 0x2c); //RXPLL_LVDSCLK_MUXSEL,PIXCLK_MUXSEL	0x2c.
		HDMI_WriteI2C_Byte(0x28, 0x24); //0x64
		printf("\r\n LvdsRxPll: set lvds port count = 2");
	} else {
		printf("\r\n LvdsRxPll: lvds port count error");
	}

	HDMI_WriteI2C_Byte(0xff, 0x81); // rxpll reset
	HDMI_WriteI2C_Byte(0x20, 0xdf);
	HDMI_WriteI2C_Byte(0x20, 0xff);

	HDMI_WriteI2C_Byte(0xff, 0x87); //RGD_RXPLL_CAL_EN. for 2nd-orderpll only.
	HDMI_WriteI2C_Byte(0x05, 0x00);

	Timer0_Delay1ms(100);
	reg_8712 = HDMI_ReadI2C_Byte(0x12);

	if (reg_8712 & 0x80) {
		printf("\r\n lvds rx pll locked");
	} else {
		printf("\r\n lvds rx pll unlocked");
	}
}

/****************************************************************
* funtion:  Desscpll 配置，当前是不支持展频的配置。 
******************************************************************/
void LT2911R_DesscPll_lvds(void)
{
	HDMI_WriteI2C_Byte(0xff, 0x82);
	//HDMI_WriteI2C_Byte(0x2d,0xb8);
	HDMI_WriteI2C_Byte(0x35, 0x82);
#if (LVDS_DESSC)
	//TO DO
#endif
}

bool LT2911R_LvdsVideoStable(struct video_timing *video_format)
{
	u32 hact, vact, sync_pol;

	HDMI_WriteI2C_Byte(0xff, 0x85);
	HDMI_WriteI2C_Byte(0x0b, 0xff); //disable vid chk irq
	HDMI_WriteI2C_Byte(0x03, 0xff);

	HDMI_WriteI2C_Byte(0xff, 0x81); //lvds rx reset
	HDMI_WriteI2C_Byte(0x0c, 0xeb);
	HDMI_WriteI2C_Byte(0x0c, 0xfb);
	Timer0_Delay1ms(100);

	HDMI_WriteI2C_Byte(0xff, 0x86);
	HDMI_WriteI2C_Byte(0x20, 0x00);
	Timer0_Delay1ms(100);

	HDMI_WriteI2C_Byte(0xff, 0x81); //video check reset
	HDMI_WriteI2C_Byte(0x10, 0xbe);
	HDMI_WriteI2C_Byte(0x10, 0xfe);
	Timer0_Delay1ms(100); //can not remove this delay

	HDMI_WriteI2C_Byte(0xff, 0x86);
	sync_pol = HDMI_ReadI2C_Byte(0x70);
	vact = HDMI_ReadI2C_Byte(0x7e);
	vact = vact * 0x100 + HDMI_ReadI2C_Byte(0x7f);

	hact = HDMI_ReadI2C_Byte(0x80);
	hact = hact * 0x100 + HDMI_ReadI2C_Byte(0x81);

	printf("\r\n hact, vact = %d, %d, %d", hact, vact, sync_pol);

	HDMI_WriteI2C_Byte(0xff, 0x86); //enable htotal and vtotal irq
	HDMI_WriteI2C_Byte(0x9e, 0xff);
	HDMI_WriteI2C_Byte(0x9e, 0x7c);

	HDMI_WriteI2C_Byte(0xff, 0x85);
	HDMI_WriteI2C_Byte(0x0b, 0xf7); //Enable vid chk irq
	HDMI_WriteI2C_Byte(0x03, 0xf7);

#if ROTATION
	if ((video_format->hact == vact) && (video_format->vact == hact)) {

		printf("\r\n LT2911R_LvdsVideoStable: video stable");
		return 1;
	} else {
		printf("\r\n LT2911R_VideoStable: video unstable");
		return 0;
	}
#else
	if ((video_format->hact == hact) && (video_format->vact == vact)) {

		printf("\r\n LT2911R_LvdsVideoStable: video stable");
		return 1;
	} else {
		printf("\r\n LT2911R_VideoStable: video unstable");
		return 0;
	}
#endif
}

bool LT2911R_LvdsClockChecked(void)
{
	u8 reg_8618;

	HDMI_WriteI2C_Byte(0xff, 0x86);
	reg_8618 = HDMI_ReadI2C_Byte(0x18);

	if ((reg_8618 & 0xf0) == 0x60) {
		//print("\r\n main loop lvds clk check: lvds clk stable");
		return 0;
	} else {
		printf("\r\n main loop lvds clk check: lvds clk unstable");
		return 1;
	}
}

bool LT2911R_LvdsPllChecked(void)
{
	u8 reg_8712;

	HDMI_WriteI2C_Byte(0xff, 0x87);
	reg_8712 = HDMI_ReadI2C_Byte(0x12);
	if (reg_8712 & 0x80) {
		//print("\r\n main loop lvds pll check: lvds rxpll locked");
		return 0;
	} else {
		printf("\r\n main loop lvds pll check: lvds rxpll unlocked");
		return 1;
	}
}

bool LT2911R_LvdsChgChecked(void)
{
#if ROTATION
	u8 reg_8510, reg_8513, reg;

	HDMI_WriteI2C_Byte(0xff, 0x85);

	reg = HDMI_ReadI2C_Byte(0x08);
	reg_8510 = HDMI_ReadI2C_Byte(0x10);
	reg_8513 = HDMI_ReadI2C_Byte(0x13);

	if (reg_8510 == 0x80) //video change and clk chang irq
	{
		printf("\r\n main loop video check: rxpll clk unstable: 0x8510 = 0x%02x", reg_8510);
		reg |= 0x80;
		HDMI_WriteI2C_Byte(0x08, reg); //clr0 bit7

		reg &= 0x7f;
		HDMI_WriteI2C_Byte(0x08, reg); //clr0
		return 1;
	} else if (reg_8513 == 0x08) //video change and clk chang irq
	{
		printf("\r\n main loop video check: lvds video changed:0x8513 = 0x%02x", reg_8513);

		HDMI_WriteI2C_Byte(0x0b, 0xff); //clr3
		HDMI_WriteI2C_Byte(0x0b, 0xf7);
		return 1;
	}

	else
		return 0;
#else // no video rotation
	return 0;
#endif
}

//////////////////////////////debug start////////////////////////////////////////////

void LT2911R_LvdsRxClkCheck_Debug(void)
{
	u32 lvds_clk;
	HDMI_WriteI2C_Byte(0xff, 0x86);
	HDMI_WriteI2C_Byte(0x00, 0x04);
	Timer0_Delay1ms(100);
	lvds_clk = HDMI_ReadI2C_Byte(0x08);

	if ((lvds_clk & 0xf0) == 0x60) {
		lvds_clk &= 0x0f;
		lvds_clk = (lvds_clk << 8) + HDMI_ReadI2C_Byte(0x09);
		lvds_clk = (lvds_clk << 8) + HDMI_ReadI2C_Byte(0x0a);
		printf("\r\n LT2911R_LvdsRxClkCheck_Debug: %d ", lvds_clk);
	} else
		printf("\r\n LT2911R_LvdsRxClkCheck_Debug: unstable");
}

//#endif
